package com.web3.management.service;

import com.web3.management.dto.response.AccountTradeProgressResponse;
import com.web3.management.dto.response.OperationLogResponse;
import com.web3.management.dto.response.StatsOverviewResponse;
import com.web3.management.dto.response.TradeDailyStatsResponse;
import com.web3.management.repository.AccountConfigRepository;
import com.web3.management.repository.AccountRepository;
import com.web3.management.repository.ConfigRepository;
import com.web3.management.repository.projection.AccountTargetProjection;
import com.web3.management.repository.projection.AccountTradeProgressProjection;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;

/**
 * 统计服务
 */
@Service
@RequiredArgsConstructor
public class StatsService {

    private final ConfigRepository configRepository;
    private final AccountRepository accountRepository;
    private final AccountConfigRepository accountConfigRepository;
    private final OperationLogService operationLogService;
    private final TradeLogService tradeLogService;

    public StatsOverviewResponse getOverview() {
        StatsOverviewResponse response = new StatsOverviewResponse();
        response.setTotalConfigs(configRepository.count());
        response.setActiveConfigs(configRepository.countByIsActive(1));
        response.setTotalAccounts(accountRepository.count());
        response.setActiveAccounts(accountRepository.countByStatus(1));
        response.setTotalAccountConfigs(accountConfigRepository.count());
        response.setActiveAccountConfigs(accountConfigRepository.countByIsActive(1));

        List<OperationLogResponse> recentLogs = operationLogService.getRecentLogs(10);
        response.setRecentOperations(recentLogs.size());
        if (!recentLogs.isEmpty()) {
            response.setLastUpdateTime(recentLogs.get(0).getCreatedAt());
        }
        BigDecimal todayTarget = accountConfigRepository.sumActiveTargetBuyQuote();
        response.setTodayPlannedAmount(todayTarget != null ? todayTarget : BigDecimal.ZERO);
        response.setTodayActualAmount(BigDecimal.ZERO);
        response.setTodaySlippage(BigDecimal.ZERO);

        TradeDailyStatsResponse todayStats = tradeLogService.getSummaryForDate(LocalDate.now());
        if (todayStats != null) {
            response.setTodayActualAmount(todayStats.getActualAmount());
            response.setTodaySlippage(todayStats.getSlippage());
        }

        return response;
    }

    public List<OperationLogResponse> getRecentOperations(int limit) {
        return operationLogService.getRecentLogs(limit);
    }

    public List<AccountTradeProgressResponse> getAccountProgress() {
        List<AccountTargetProjection> targetProjections = accountConfigRepository.sumActiveTargetBuyQuoteGroupByAccount();
        Map<Integer, BigDecimal> targetMap = targetProjections.stream()
                .collect(Collectors.toMap(AccountTargetProjection::getAccountId, AccountTargetProjection::getTargetAmount));

        List<AccountTradeProgressProjection> progressProjections = tradeLogService.aggregateAccountSummaryByDate(LocalDate.now());
        Map<Integer, BigDecimal> actualMap = new HashMap<>();
        Map<Integer, BigDecimal> slippageMap = new HashMap<>();
        for (AccountTradeProgressProjection projection : progressProjections) {
            actualMap.put(projection.getAccountId(), projection.getTotalActualAmount());
            slippageMap.put(projection.getAccountId(), projection.getTotalSlippage());
        }

        return accountRepository.findAll().stream().map(account -> {
            AccountTradeProgressResponse response = new AccountTradeProgressResponse();
            response.setAccountId(account.getId());
            response.setAccountName(account.getName());
            response.setAccountStatus(account.getStatus());

            BigDecimal target = targetMap.getOrDefault(account.getId(), BigDecimal.ZERO);
            BigDecimal actual = actualMap.getOrDefault(account.getId(), BigDecimal.ZERO);
            BigDecimal slippage = slippageMap.getOrDefault(account.getId(), BigDecimal.ZERO);

            response.setTargetAmount(target);
            response.setActualAmount(actual);
            response.setSlippage(slippage);

            BigDecimal progress = BigDecimal.ZERO;
            if (target != null && target.compareTo(BigDecimal.ZERO) > 0) {
                progress = actual.divide(target, 4, RoundingMode.HALF_UP);
            }
            response.setProgressRate(progress);
            return response;
        }).collect(Collectors.toList());
    }
}
